package com.googlecode.bipol.war.google.apis.chart;

import static com.googlecode.charts4j.Color.SKYBLUE;
import static com.googlecode.charts4j.Color.WHITE;

import com.googlecode.bip.dao.deprecated.CategoryDAO;
//import com.googlecode.bip.entity.IUserValue;
import com.googlecode.bip.entity.deprecated.Category;
import com.googlecode.bip.entity.deprecated.UserValue;
//import com.googlecode.bipol.war.session.BiPolSession;
import com.googlecode.charts4j.Color;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
import com.googlecode.charts4j.AxisLabels;
import com.googlecode.charts4j.AxisLabelsFactory;
import com.googlecode.charts4j.AxisStyle;
import com.googlecode.charts4j.AxisTextAlignment;
import com.googlecode.charts4j.Data;
import com.googlecode.charts4j.DataUtil;
import com.googlecode.charts4j.Fills;
import com.googlecode.charts4j.GCharts;
import com.googlecode.charts4j.Line;
import com.googlecode.charts4j.LineChart;
import com.googlecode.charts4j.LineStyle;
import com.googlecode.charts4j.Plots;
import com.googlecode.charts4j.Shape;

/**
 * 
 * @author Claude CHOISNET
 */
@Deprecated // TODO: REMOVE
public class LineChar
{
    private static Logger slogger = Logger.getLogger( LineChar.class );
    //private BiPolSession uSession;
    private CategoryDAO categoryDB;
    /* Map<idcategory,Map<Timestamp,UserValue>> */
    private final LinkedHashMap<Integer,HashMap<Timestamp,UserValue>> valuesMap = new LinkedHashMap<Integer,HashMap<Timestamp,UserValue>>();
    private final LinkedHashMap<Integer,Category> categoryMap = new LinkedHashMap<Integer,Category>();
    private String title;
    private Calendar fromCalendar;
    private Calendar toCalendar;


    private final static Color[] _colorsLines = {
        Color.newColor( "CA3D05" ),
        SKYBLUE,
        Color.AQUA,
        Color.BLUEVIOLET,
        };
    
    /**
     * 
     * @param uSession
     * @throws NamingException 
     * @throws SQLException 
     */
    public LineChar( 
//        final BiPolSession uSession
        )
    {
//        this.uSession   = uSession;
        this.categoryDB = new CategoryDAO();
    }

    /**
     * @return the title
     */
    public String getTitle()
    {
        return title;
    }

    /**
     * @param title the title to set
     */
    public void setTitle( String title )
    {
        this.title = title;
    }

    /**
     * 
     * @return
     */
    public Map<Integer,HashMap<Timestamp,UserValue>> getValuesMap()
    //public Map<Integer,List<UserValue>> getValuesMap()
    {
        return Collections.unmodifiableMap( valuesMap );
    }
    
//    /**
//     * 
//     * @return
//     */
//    public Map<Integer,HashMap<Timestamp,UserValue>> _getValuesMap()
//    //public Map<Integer,List<UserValue>> getValuesMap()
//    {
//        //return Collections.unmodifiableMap( valuesMap );
//        Collection<HashMap<Timestamp, UserValue>> treturn = valuesMap.values();
//        
//        return nuul;
//    }

    /**
     * Add values for this category
     * @param catagory
     * @param userValueList
     * @throws IllegalArgumentException
     * @throws NamingException 
     * @throws SQLException 
     */
    public void add(
        final int               idcategory,
        final List<UserValue>   userValueList
        )
        throws IllegalArgumentException, SQLException, NamingException
    {
        final Category category = categoryDB.getCategory(
                userValueList.get( 0 ).getIdcategory(),
                "uSession.getIdlocal()"
                );
        HashMap<Timestamp,UserValue> timeValues = new HashMap<Timestamp,UserValue>();
        
        for( UserValue uv: userValueList ) {
            if( uv.getIdcategory() != idcategory ) {
                throw new IllegalArgumentException( "Category mismatch" );
                }
//            dateSet.add( uv.getUserdate() );
            timeValues.put( uv.getUserdate(), uv );
            }

//        final List<UserValue> old = valuesMap.put( idcategory, userValueList );
        final HashMap<Timestamp, UserValue> old = valuesMap.put( idcategory, timeValues );

        if( old != null ) {
            throw new IllegalArgumentException( "Category already added" );
            }

        categoryMap.put( idcategory, category );
    }

    private void computeFirstAndLastCalendar()
    {
        Timestamp firstTS = null;
        Timestamp lastTS  = null;
        
        for( HashMap<Timestamp,UserValue> timeUserValueMap : valuesMap.values() ) {
            for( Timestamp ts : timeUserValueMap.keySet() ) {
                if( lastTS == null ) {
                    lastTS = ts;
                    }
                if( firstTS == null ) {
                    firstTS = ts;
                    }
                if( ts.after( lastTS ) ) {
                    lastTS = ts;
                    }
                if( ts.before( firstTS ) ) {
                    firstTS = ts;
                    }
                }
            }

        this.fromCalendar = new GregorianCalendar();
        fromCalendar.setTime( firstTS );
        
        this.toCalendar   = new GregorianCalendar();
        toCalendar.setTime( lastTS );
    }
    
    /**
     * Fill missing values for missing time stamps
     */
    private void fixMissingValues(
            final Category                      category,
            final HashMap<Timestamp,UserValue>  timeValues
            )
    {
        Calendar c = Calendar.class.cast( fromCalendar.clone() );

        while( c.compareTo( toCalendar ) <= 0 ) {
            Timestamp ts = new Timestamp( c.getTimeInMillis() );
            UserValue uv = timeValues.get( ts );

            if( uv == null ) {
                // No values for this date
                uv = new UserValue();

                // TODO: improve this !
                uv.setUservalue( category.getDefaultvalue() );

                // Add computed value
                timeValues.put( ts, uv );
                }

            c.add( Calendar.DAY_OF_MONTH, 1 );
            }
    }
    
    public String toURLString()
    {
        final int         linesCount  = valuesMap.size();
        final Line[]      lines       = new Line[ linesCount ];
        final int[]       categories  = new int[ linesCount ];
        int               l           = 0;

//        // Compute by date
//        for( Map.Entry<Integer,List<UserValue>> entry : valuesMap.entrySet() ) {
//            final List<UserValue> uvList = entry.getValue();
//
//            // prepare labels and synchronize values
//            for( UserValue uc : uvList ) {
//                dateMap.add( uc.getUserdate(), uc );
//                }
//            categories[ l++ ] = entry.getKey();
//            }

        computeFirstAndLastCalendar();        
        
        int checkValueSize = -1; // TODO: remove this
        
        // Fix missing values for all categories
        for( Map.Entry<Integer, Category> entry : categoryMap.entrySet() ) {
            fixMissingValues(
                entry.getValue(), 
                valuesMap.get( entry.getKey() )
                );
            
            if( checkValueSize < 0 ) {
                checkValueSize = valuesMap.get( entry.getKey() ).size();
                }
            else {
                if( checkValueSize != valuesMap.get( entry.getKey() ).size() ) {
                    slogger.fatal( "bad size found '" 
                            + valuesMap.get( entry.getKey() ).size()
                            + "' expecting for "
                            + entry.getValue()
                            );
                    }
                }

            categories[ l++ ] = entry.getKey();
            }

        //final int         valuesCount = dateMap.keySize();
        final int         valuesCount = valuesMap.values().iterator().next().size();
        final double[][]  linesvalues = new double[ linesCount ][ valuesCount ];
        
        slogger.info( "linesCount  = " + linesCount );
        slogger.info( "valuesCount = " + valuesCount );
        
        {
            int linecol = 0; // date
            
//            for( Map.Entry<Timestamp,Collection<UserValue>> de : dateMap.entrySet() ) {
//                for(int i =0; i<linesCount; i++ ) {
//                    final int idcategory = categories[ i ];
//                    final int v          = getValue( de.getKey(), idcategory );
//                    linesvalues[ i ][ col ] = v;
//                    }
//                col++;
//                }
            Calendar c = Calendar.class.cast( fromCalendar.clone() );

            // Pour chaque date.
            while( c.compareTo( toCalendar ) <= 0 ) {
                int         valueRow = 0;
                Timestamp   ts       = new Timestamp( c.getTimeInMillis() );

                // Pour chaque category
                for( Map.Entry<Integer,HashMap<Timestamp,UserValue>> entry : valuesMap.entrySet() ) {
                    UserValue   uv = entry.getValue().get( ts );
                    int         v;
                    
                    if( uv == null ) {
                        v = 0;
                        }
                    else {
                        v = uv.getUservalue();
                        }

                    linesvalues[ valueRow ][ linecol ] = v;

                    valueRow++;
                    }

                c.add( Calendar.DAY_OF_MONTH, 1 );
                linecol++;
            }
        }
        
//        for(int i=0;i<linesvalues.length;i++) {
//            for( int j=0;j<linesvalues[i].length;j++ ) {
//                System.out.printf( "v[%d][%d]=%s\n", i, j, linesvalues[i][j] );
//                }
//            }
        
        for( l = 0; l<linesCount; l++ ) {
            int idcategory = categories[ l ];
            //final List<UserValue> uvList = entry.getValue();
            //final int             size   = uvList.size();
//            linesvalues[ l ] = new double[ size ];
//            
//            for( int i = 0; i<size; i++) {
//                linesvalues[ 0 ][ i ] = uvList.get( i ).getUservalue();
//                }

            Category category = categoryMap.get( idcategory );

            slogger.info( "categoryMap = " + categoryMap );
            slogger.info( "idcategory = " + idcategory );
            slogger.info( "line = " + l + " - category = " + category );

            //Data     data     = Data.newData( linesvalues[ l ] );
            Data     data     = DataUtil.scaleWithinRange( 
                                    category.getMinvalue(),
                                    category.getMaxvalue(),
                                    linesvalues[ l ] 
                                     );
            lines[l] = Plots.newLine(
                    data, 
                    getColorLine( l ), 
                    category.getName()
                    );
            lines[l].setLineStyle(LineStyle.newLineStyle(3, 1, 0));
            lines[l].addShapeMarkers(Shape.DIAMOND, Color.newColor("CA3D05"), 12);
            lines[l].addShapeMarkers(Shape.DIAMOND, Color.WHITE, 8);
            }
        
//        for(int i=0;i<lines.length;i++) {
//            System.out.printf( "lines[%d]=%s\n", i, lines[i] );
//            }
        
//        l = 0;
//        for( Map.Entry<Integer,List<UserValue>> entry : valuesMap.entrySet() ) {
//            final List<UserValue> uvList = entry.getValue();
//            final int             size   = uvList.size();
//            
//            linesvalues[ l ] = new double[ size ];
//            
//            for( int i = 0; i<size; i++) {
//                linesvalues[ l ][ i ] = uvList.get( i ).getUservalue();
//                }
//            
//            Category category = categoryMap.get( entry.getKey() );
//            
//            lines[l] = Plots.newLine(
//                    DataUtil.scaleWithinRange( 
//                            category.getMinvalue(),
//                            category.getMaxvalue(),
//                            linesvalues[ l ] 
//                            ),
//                    //Data.newData( linesvalues[ l ] ), 
//                    colorsLines[ l ], 
//                    category.getName()
//                    );
//            lines[l].setLineStyle(LineStyle.newLineStyle(3, 1, 0));
//            lines[l].addShapeMarkers(Shape.DIAMOND, Color.newColor("CA3D05"), 12);
//            lines[l].addShapeMarkers(Shape.DIAMOND, Color.WHITE, 8);
//
//            l++;
//            }

        
/*
        
        //FAKE TODO
        for(int i = 0; i < numPoint; i++) {
            linesvalues[ 1 ][ i ] = (Math.cos(30*i*Math.PI/180)*10 + 50)*i/20;
            }
        lines[1] = Plots.newLine(Data.newData(linesvalues[ 1 ]), SKYBLUE, "Competition.com");
        lines[1].setLineStyle(LineStyle.newLineStyle(3, 1, 0));
        lines[1].addShapeMarkers(Shape.DIAMOND, SKYBLUE, 12);
        lines[1].addShapeMarkers(Shape.DIAMOND, Color.WHITE, 8);
*/        
        // Defining lines
        //final int NUM_POINTS = 25;
        //final double[] competition  = new double[NUM_POINTS];
        //final double[] mywebsite    = new double[NUM_POINTS];

//        for (int i = 0; i < numPoint; i++) {
//            competition[i] = 100-(Math.cos(30*i*Math.PI/180)*10 + 50)*i/20;
//            mywebsite[i] = (Math.cos(30*i*Math.PI/180)*10 + 50)*i/20;
//            }
        

        // Defining chart.
        LineChart chart = GCharts.newLineChart( lines );
        chart.setSize(600, 450);
        chart.setTitle(
            title, //"Utilisateur:" + uSession.getUsername(),
            Color.BROWN, 
            14
            );
        //chart.addHorizontalRangeMarker(40, 60, Color.newColor(RED, 30));
        //chart.addVerticalRangeMarker(70, 90, Color.newColor(GREEN, 30));
        chart.setGrid(25, 25, 3, 2);

        // Defining axis info and styles
        AxisStyle axisStyle = AxisStyle.newAxisStyle(WHITE, 12, AxisTextAlignment.CENTER);

//List<? extends String> x;
        //
        AxisLabels xAxis1 = AxisLabelsFactory.newAxisLabels("Nov", "Mar");
        //AxisLabels xAxis1 = AxisLabelsFactory.newAxisLabels("Nov", "Dec", "Jan", "Feb", "Mar");
        //AxisLabels xAxis1 = AxisLabelsFactory.newAxisLabels((String[])null);
        xAxis1.setAxisStyle(axisStyle);

        //AxisLabels xAxis2 = AxisLabelsFactory.newAxisLabels("2007", "2008");
        //AxisLabels xAxis2 = AxisLabelsFactory.newAxisLabels("2007", "2007", "2008", "2008", "2008");
        //xAxis2.setAxisStyle(axisStyle);
        
        AxisLabels yAxis = AxisLabelsFactory.newAxisLabels("", "1/4", "1/2", "3/4", "1");
        //AxisLabels xAxis3 = AxisLabelsFactory.newAxisLabels("Month", 50.0);

        //xAxis3.setAxisStyle(AxisStyle.newAxisStyle(WHITE, 14, AxisTextAlignment.CENTER));
        yAxis.setAxisStyle(axisStyle);

        AxisLabels yAxis2 = AxisLabelsFactory.newAxisLabels("Valeur", 50.0);
        yAxis2.setAxisStyle(AxisStyle.newAxisStyle(WHITE, 14, AxisTextAlignment.CENTER));
        yAxis2.setAxisStyle(axisStyle);

        // Adding axis info to chart.
        chart.addXAxisLabels(xAxis1);
        //chart.addXAxisLabels(xAxis2);
        //chart.addXAxisLabels(xAxis3);
        chart.addYAxisLabels(yAxis);
        chart.addYAxisLabels(yAxis2);

        // Defining background and chart fills.
        chart.setBackgroundFill(Fills.newSolidFill(Color.newColor("AAAAAA")));
        //LinearGradientFill fill = Fills.newLinearGradientFill(0, Color.newColor("363433"), 100);
        //fill.addColorAndOffset(Color.newColor("2E2B2A"), 0);
        //chart.setAreaFill(fill);

        return chart.toURLString();
    }
    
    private Color getColorLine( final int line )
    {
        return LineChar._colorsLines[ line % LineChar._colorsLines.length ];
    }

}

//private int getValue(Timestamp ts, int idcategory )
//{
//  Collection<UserValue> lv = dateMap.getCollection( ts );
//  
//  if( lv == null ) {
//      throw new IllegalArgumentException( "Timestamp not found:" + ts );
//      }
//  
//  for(UserValue uv: lv) {
//      if( uv.getIdcategory() == idcategory ) {
//          return uv.getUservalue();
//      }
//  }
//  
//  // No value for this date
//  Category c = categoryMap.get( idcategory );
//
//  if( c == null ) {
//      throw new IllegalArgumentException( "idcategory not found:" + idcategory );
//      }
//  
//  int v = c.getMinvalue(); // TODO !!!!!idcategory
//  
//  slogger.info( "No value for: " + ts + " idcategory = " + idcategory + " SET =" + v );
//  
//  return v;
//}


